﻿using System.Collections.Generic;
using JetBlack.TopicBus.Messages;

namespace JetBlack.TopicBus.Distributor
{
    internal class PublisherManager
    {
        internal delegate void OnStalePublisherHandler(Interactor publisher, IEnumerable<string> staleTopics);
        internal event OnStalePublisherHandler OnStalePublisher;

        internal readonly Dictionary<string, List<Interactor>> TopicToPublisherMap = new Dictionary<string, List<Interactor>>();
        internal readonly Dictionary<Interactor, List<string>> PublisherToTopicMap = new Dictionary<Interactor, List<string>>();

        internal void Publish(Interactor publisher, Interactor subscriber, ClientMessage message)
        {
            Remember(message.Topic, publisher);
            subscriber.SendMessage(message);
        }

        internal void Publish(Interactor publisher, Interactor subscriber, SubscriberMessage message)
        {
            Remember(message.Topic, publisher);
            subscriber.SendMessage(message);
        }

        private void Remember(string topic, Interactor publisher)
        {
            if (!TopicToPublisherMap.ContainsKey(topic))
                TopicToPublisherMap.Add(topic, new List<Interactor>());
            if (!TopicToPublisherMap[topic].Contains(publisher))
                TopicToPublisherMap[topic].Add(publisher);

            if (!PublisherToTopicMap.ContainsKey(publisher))
                PublisherToTopicMap.Add(publisher, new List<string>());
            if (!PublisherToTopicMap[publisher].Contains(topic))
                PublisherToTopicMap[publisher].Add(topic);
        }

        internal void Remove(Interactor publisher)
        {
            List<string> staleTopics = new List<string>();

            if (PublisherToTopicMap.ContainsKey(publisher))
            {
                foreach (string topic in PublisherToTopicMap[publisher])
                {
                    if (TopicToPublisherMap.ContainsKey(topic))
                    {
                        if (TopicToPublisherMap[topic].Contains(publisher))
                        {
                            TopicToPublisherMap[topic].Remove(publisher);
                            if (TopicToPublisherMap[topic].Count == 0)
                            {
                                TopicToPublisherMap.Remove(topic);
                                staleTopics.Add(topic);
                            }
                        }
                    }
                }

                PublisherToTopicMap.Remove(publisher);
            }

            if (OnStalePublisher != null)
                OnStalePublisher(publisher, staleTopics);
        }
    }
}
